package org.cloudbus.cloudsim.examples;

/*
 * Title:        CloudSim Toolkit
 * Description:  CloudSim (Cloud Simulation) Toolkit for Modeling and Simulation
 *               of Clouds
 * Licence:      GPL - http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (c) 2009, The University of Melbourne, Australia
 */

import java.text.DecimalFormat;//处理文本、日期、数字和消息的类和接口,十进制格式
import java.util.ArrayList;//Java的实用工具类库java.util包
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;

import org.cloudbus.cloudsim.Cloudlet;
import org.cloudbus.cloudsim.CloudletSchedulerTimeShared;
import org.cloudbus.cloudsim.Datacenter;
import org.cloudbus.cloudsim.DatacenterBroker;
import org.cloudbus.cloudsim.DatacenterCharacteristics;
import org.cloudbus.cloudsim.Host;
import org.cloudbus.cloudsim.Log;
import org.cloudbus.cloudsim.Pe;
import org.cloudbus.cloudsim.Storage;
import org.cloudbus.cloudsim.UtilizationModel;
import org.cloudbus.cloudsim.UtilizationModelFull;
import org.cloudbus.cloudsim.Vm;
import org.cloudbus.cloudsim.VmAllocationPolicySimple;
import org.cloudbus.cloudsim.VmSchedulerTimeShared;
import org.cloudbus.cloudsim.core.CloudSim;
import org.cloudbus.cloudsim.provisioners.BwProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.PeProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.RamProvisionerSimple;

/**
 * 创建一个含一台主机的数据中心，并在其上运行一个云任务
 */
public class CloudSimExample1 {

	
	private static List<Cloudlet> cloudletList;//云任务列表 
	private static List<Vm> vmlist;//虚拟机列表 

	public static void main(String[] args) {
		//打印
		Log.printLine("Starting CloudSimExample1...");
		
		try {
			
			//初始化工具包***************************************
			int num_user = 1; // 用户数量
			Calendar calendar = Calendar.getInstance();//?
			boolean trace_flag = false; // 跟踪事件		
			CloudSim.init(num_user, calendar, trace_flag);//初始化CloudSim程序库
			//*******************************************************

			// 创建数据中心对象
			@SuppressWarnings("unused")
			Datacenter datacenter0 = createDatacenter("Datacenter_0");

			// 创建代理对象
			DatacenterBroker broker = createBroker();
			int brokerId = broker.getId();//获得用户ID
			System.out.println("****************"+brokerId);

			// 创建一个虚拟机列表
			vmlist = new ArrayList<Vm>();

			// VM description虚拟机参数
			int vmid = 0;//虚拟机的ID
			int mips = 1000;//运行该任务虚拟机的执行速度
			long size = 10000; // image size (MB)外存
			int ram = 512; // vm memory (MB)内存
			long bw = 1000;//带宽
			int pesNumber = 1; // number of cpus CPU个数
			String vmm = "Xen"; // VMM name虚拟机监控器的名字

			// create VM虚拟机创建
			Vm vm = new Vm(vmid, brokerId, mips, pesNumber, ram, bw, size, vmm, new CloudletSchedulerTimeShared());

			// 把虚拟机对象加入虚拟机列表
			vmlist.add(vm);

			// 把虚拟机列表提交给代理
			broker.submitVmList(vmlist);

			// 创建一个云任务列表
			cloudletList = new ArrayList<Cloudlet>();

			// 云任务参数
			int id = 0;//任务的用户ID
			long length = 400000;//执行任务请求的PE数
			long fileSize = 300;//云任务文件大小
			long outputSize = 300;//云任务输出文件的大小
			UtilizationModel utilizationModel = new UtilizationModelFull();
			//创建云让任务
			Cloudlet cloudlet = new Cloudlet(id, length, pesNumber, fileSize, outputSize, utilizationModel, utilizationModel, utilizationModel);
			cloudlet.setUserId(brokerId);
			cloudlet.setVmId(vmid);

			// 云任务加入列表
			cloudletList.add(cloudlet);

			// 把云任务列表提交给代理
			broker.submitCloudletList(cloudletList);

			// 开始仿真
			CloudSim.startSimulation();
			//结束仿真
			CloudSim.stopSimulation();

			//仿真结束 打印结果
			List<Cloudlet> newList = broker.getCloudletReceivedList();
			printCloudletList(newList);

			Log.printLine("CloudSimExample1 finished!");
		} catch (Exception e) {
			e.printStackTrace();
			Log.printLine("Unwanted errors happen");
		}
	}

	
	//创建数据中心
	private static Datacenter createDatacenter(String name) {

		// Here are the steps needed to create a PowerDatacenter:
		// 1. We need to create a list to store
		// our machine创建列表储存主机
		List<Host> hostList = new ArrayList<Host>();

		// 2. A Machine contains one or more PEs or CPUs/Cores.一个机器含有的处理器
		// In this example, it will have only one core.在这个例子中，机器只有一个核心
		//
		List<Pe> peList = new ArrayList<Pe>();

		int mips = 1000;//处理器处理速度
		// 3. Create PEs and add these into a list.创建处理器 并添加到Pe列表
		peList.add(new Pe(0, new PeProvisionerSimple(mips))); // need to store Pe id and MIPS Rating
		//生成CPU对象，各参数是：（处理器ID，处理速度）
		// 4. Create Host with its id and list of PEs and add them to the list
		// of machines创建主机
		int hostId = 0;
		int ram = 2048; // host memory (MB)//内存大小
		long storage = 1000000; // host storage//存储空间大小
		int bw = 10000;//带宽
		//参数分别是：（主机ID，内存大小，带宽，硬盘大小，CPU数目列表，虚拟机时间共享？）
		
		hostList.add(
			new Host(
				hostId,
				new RamProvisionerSimple(ram),
				new BwProvisionerSimple(bw),
				storage,
				peList,
				new VmSchedulerTimeShared(peList)//虚拟机时间共享
			)
		); // This is our machine

		// 5. Create a DatacenterCharacteristics object that stores the
		// properties of a data center: architecture, OS, list of
		// Machines, allocation policy: time- or space-shared, time zone
		// and its price (G$/Pe time unit).创建数据中心特征对象
		String arch = "x86"; // system architecture系统架构
		String os = "Linux"; // operating system操作系统
		String vmm = "Xen";//虚拟机管理程序
		double time_zone = 10.0; // time zone this resource located这个资源所在的时区
		double cost = 3.0; // the cost of using processing in this resource处理成本
		double costPerMem = 0.05; // the cost of using memory in this resource内存成本
		double costPerStorage = 0.001; // the cost of using storage in this
										// resource存储成本
		double costPerBw = 0.0; // the cost of using bw in this resource带宽成本
		LinkedList<Storage> storageList = new LinkedList<Storage>(); // we are not adding SAN
													// devices by now我们现在还不添加存储区域网

		DatacenterCharacteristics characteristics = new DatacenterCharacteristics(
				arch, os, vmm, hostList, time_zone, cost, costPerMem,
				costPerStorage, costPerBw);

		// 6. Finally, we need to create a PowerDatacenter object.创建数据中心对象
		Datacenter datacenter = null;
		try {
			datacenter = new Datacenter(name, characteristics, new VmAllocationPolicySimple(hostList), storageList, 0);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return datacenter;
	}

	 //创建数据中心代理
	private static DatacenterBroker createBroker() {
		DatacenterBroker broker = null;
		try {
			broker = new DatacenterBroker("Broker");
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return broker;
	}
	
	 //打印云任务对象	
	private static void printCloudletList(List<Cloudlet> list) {
		int size = list.size();
		Cloudlet cloudlet;

		String indent = "    ";
		Log.printLine();
		Log.printLine("========== OUTPUT ==========");
		Log.printLine("Cloudlet ID" + indent + "STATUS" + indent
				+ "Data center ID" + indent + "VM ID" + indent + "Time" + indent
				+ "Start Time" + indent + "Finish Time");

		DecimalFormat dft = new DecimalFormat("###.##");//保留两位小数吗？
		for (int i = 0; i < size; i++) {
			cloudlet = list.get(i);
			Log.print(indent + cloudlet.getCloudletId() + indent + indent);

			if (cloudlet.getCloudletStatus() == Cloudlet.SUCCESS) {
				Log.print("SUCCESS");

				Log.printLine(indent + indent + cloudlet.getResourceId()
						+ indent + indent + indent + cloudlet.getVmId()
						+ indent + indent
						+ dft.format(cloudlet.getActualCPUTime()) + indent
						+ indent + dft.format(cloudlet.getExecStartTime())
						+ indent + indent
						+ dft.format(cloudlet.getFinishTime()));
			}
		}
	}

}